﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace NMoq.Core
{
    public abstract class Selector<T>:ISelector<T> where T:IAction
    {
        #region properties
        protected  Dictionary<int, T> MethodActionMapper
        { get; set; }

        protected T DefaultAction
        { get; set; }

        protected bool ActionAllMethod
        { get; set; }
        #endregion

        #region constructors
        public Selector()
        { 
        }

        public Selector(T action)
            :this()
        {
            if (action == null)
                throw new MockException("parameter target should not be null!");

            ActionAllMethod = false;
            DefaultAction = action;
            MethodActionMapper = new Dictionary<int, T>();
        }

        public Selector(bool actionAllMethod,T action)
            : this(action)
        {
            if (action == null)
                throw new MockException("parameter target should not be null!");

            ActionAllMethod = actionAllMethod;
        }
        #endregion

        #region ISelector<T> Members

        public virtual T Select(MethodMessageInfo methodMessageInfo)
        {
            if (ActionAllMethod)
                return DefaultAction;

            int methodHashCode = IdentifierFactory.GetIndentifier<T>(methodMessageInfo );
            if (MethodActionMapper.ContainsKey (methodHashCode ))
                return MethodActionMapper[methodHashCode];

            return default(T); 
        }

        public virtual void Setup(MethodMessageInfo methodMessgeInfo)
        {
            Setup(methodMessgeInfo, DefaultAction);
        }

        public virtual void Setup(MethodMessageInfo methodMessageInfo, T target)
        {
            if (target == null)
                target = DefaultAction;

            int methodHashCode = IdentifierFactory.GetIndentifier<T>(methodMessageInfo);
            if (MethodActionMapper.ContainsKey(methodHashCode))
                MethodActionMapper[methodHashCode] = target;
            else
                MethodActionMapper.Add (methodHashCode ,target );
        }

        public virtual void Setup(MethodMessageInfo methodMessageInfo, Func<MethodMessageInfo ,IEnumerable<T>, T> selectFunc)
        {
            T action = default(T);

            if (selectFunc != null)
                action = selectFunc(methodMessageInfo,MethodActionMapper.Values);

            if (action == null)
                action = DefaultAction;

            int methodHashCode = IdentifierFactory.GetIndentifier<T>(methodMessageInfo);
            if (MethodActionMapper.ContainsKey(methodHashCode))
                MethodActionMapper[methodHashCode] = action;
            else
                MethodActionMapper.Add(methodHashCode, action);
        }

        public virtual void Clear(MethodMessageInfo methodMessageInfo)
        {
            int methodHashCode = IdentifierFactory.GetIndentifier<T>(methodMessageInfo);
            if (MethodActionMapper.ContainsKey(methodHashCode))
                MethodActionMapper.Remove(methodHashCode); 
        }

        public virtual  T Select()
        {
            return DefaultAction ;
        }

        public virtual  void Setup(T target)
        {
            ActionAllMethod = true ;
            if(target !=null )
                DefaultAction = target;
        }

        public virtual  void Clear()
        {
            ActionAllMethod = false ; 
        }

        public virtual void CallDefaultAction(MethodMessageInfo methodMessageInfo,Action<MethodMessageInfo ,T> action)
        {
            action(methodMessageInfo,DefaultAction);
        }

        public virtual void CallAction(MethodMessageInfo methodMessageInfo, Action<MethodMessageInfo, T> action)
        {
            T actionTarget = Select(methodMessageInfo);
            if(actionTarget !=null )
                action(methodMessageInfo, actionTarget);
        }
        #endregion
    }

  

    
}
